package com.freedom.auth.infrastructure.extension.mobile;

import com.freedom.common.core.constant.SmsConstants;
import com.freedom.common.core.enums.AuthResultCodeEnum;
import com.freedom.common.framework.exception.ServiceException;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 手机验证码授权者
 *
 */
public class SmsCodeTokenGranter extends AbstractTokenGranter {

    /**
     * 声明授权者 SmsCodeTokenGranter 支持授权模式 sms_code
     * 根据接口传值 grant_type = sms_code 的值匹配到此授权者
     * 匹配逻辑详见下面的两个方法
     *
     * @see CompositeTokenGranter#grant(String, TokenRequest)
     * @see AbstractTokenGranter#grant(String, TokenRequest)
     */
    private final AuthenticationManager authenticationManager;

    private static final String GRANT_TYPE = "sms_code";

    public SmsCodeTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                               OAuth2RequestFactory requestFactory, AuthenticationManager authenticationManager) {
        super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
        // 手机号
        String mobile = parameters.get(SmsConstants.MOBILE_KEY);
        // 短信验证码
        String code = parameters.get(SmsConstants.MOBILE_CODE);
        // 短信验证码类型
        String codeType = parameters.get(SmsConstants.MOBILE_CODE_TYPE);

        parameters.remove(SmsConstants.MOBILE_CODE);

        try {
            Authentication userAuth = new SmsCodeAuthenticationToken(mobile, code, codeType);
            ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

            userAuth = this.authenticationManager.authenticate(userAuth);

            if (Objects.nonNull(userAuth) && userAuth.isAuthenticated()) {
                OAuth2Request oAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
                return new OAuth2Authentication(oAuth2Request, userAuth);
            } else {
                throw new ServiceException(AuthResultCodeEnum.LOGIN_PARAM_ERROR);
            }
        } catch (AccountStatusException var8) {
            throw new ServiceException(AuthResultCodeEnum.ACCOUNT_ERROR);
        } catch (BadCredentialsException var9) {
            throw new ServiceException(AuthResultCodeEnum.LOGIN_PARAM_ERROR);
        }
    }
}
